package com.joekai.view_demo.message_drag;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.BounceInterpolator;

import androidx.annotation.Nullable;

import com.joekai.view_demo.utils.BubbleUtils;
import com.joekai.view_demo.utils.PxUtils;

public class MessageDragView extends View {
    private PointF mFixedPoint, mDragPoint;

    //拖拽圆半径
    private int mDragRadius = 15;

    private Paint mPaint;

    private int mFixedRadiusMax = 12;
    private int mFixedRadiusMin = 4;

    private int mFixedRadius;

    private Bitmap mDragBitmap;
    private MessageDragListener mListener;
    public MessageDragView(Context context) {
        this(context,null);
    }

    public MessageDragView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public MessageDragView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr,0);
    }

    public MessageDragView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        mDragRadius = PxUtils.dp2px(mDragRadius);
        mFixedRadiusMax = PxUtils.dp2px(mFixedRadiusMax);
        mFixedRadiusMin = PxUtils.dp2px(mFixedRadiusMin);
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        if (mDragPoint == null || mFixedPoint == null) {
            return;
        }
        canvas.drawCircle(mDragPoint.x, mDragPoint.y, mDragRadius, mPaint);
//        mFixedRadius = (int) (mFixedRadiusMax - getDistance(mDragPoint, mFixedPoint) / 20);
        Path besselPath = getBesselPath();
        if (besselPath != null) {
            canvas.drawCircle(mFixedPoint.x, mFixedPoint.y, mFixedRadius, mPaint);
            canvas.drawPath(besselPath, mPaint);
        }
//        else {
//            canvas.drawCircle(mFixedPoint.x, mFixedPoint.y, PxUtils.dp2px(mFixedRadiusMin), mDragPaint);
//        }
        if (mDragBitmap != null)
            canvas.drawBitmap(mDragBitmap, mDragPoint.x - mDragBitmap.getWidth() / 2 , mDragPoint.y - mDragBitmap.getHeight() / 2, null);
    }
    private Path getBesselPath() {
        double distance = getDistance(mDragPoint, mFixedPoint);

        mFixedRadius = (int) (mFixedRadiusMax - distance / 20);
        Log.e("_____TAG", mFixedRadius + "?" + mFixedRadiusMin);
        if (mFixedRadius < mFixedRadiusMin) {
            return null;
        }
        //求斜率
        float dx = mDragPoint.x - mFixedPoint.x;
        float dy = mDragPoint.y - mFixedPoint.y;
        float tanA = dy / dx;

        //求角A
        double arcA = Math.atan(tanA);
        float p0x = (float) (mFixedPoint.x + mFixedRadius * Math.sin(arcA));
        float p0y = (float) (mFixedPoint.y - mFixedRadius * Math.cos(arcA));

        float p1x = (float) (mDragPoint.x + mDragRadius * Math.sin(arcA));
        float p1y = (float) (mDragPoint.y - mDragRadius * Math.cos(arcA));

        float p2x = (float) (mDragPoint.x - mDragRadius * Math.sin(arcA));
        float p2y = (float) (mDragPoint.y + mDragRadius * Math.cos(arcA));

        float p3x = (float) (mFixedPoint.x - mFixedRadius * Math.sin(arcA));
        float p3y = (float) (mFixedPoint.y + mFixedRadius * Math.cos(arcA));
        Path besselPath = new Path();

        besselPath.moveTo(p0x, p0y);
        //两个点 ，第一个控制点  第二个

        PointF controlPoint = getControlPoint();

        besselPath.quadTo(controlPoint.x, controlPoint.y, p1x, p1y);
        besselPath.lineTo(p2x, p2y);
        besselPath.quadTo(controlPoint.x, controlPoint.y, p3x, p3y);
        besselPath.close();
        return besselPath;
    }
    /*
   获取控制点
    */
    private PointF getControlPoint() {
//        Log.e("---TAG","mDragPoint.x: "+mDragPoint.x+" mFixedPoint.x: "+mFixedPoint.x+" mDragPoint.y: "+mDragPoint.y+" mFixedPoint.y: "+mFixedPoint.y);
        return new PointF((mDragPoint.x + mFixedPoint.x) / 2, (mDragPoint.y + mFixedPoint.y) / 2);
    }

    private double getDistance(PointF p1, PointF p2) {
        float dx = p1.x - p2.x;
        float dy = p1.y - p2.y;
        return Math.sqrt((dx * dx + dy * dy));

    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                float downX = event.getX();
                float downY = event.getY();
                initPoint(downX, downY);
                break;
            case MotionEvent.ACTION_MOVE:
                float moveX = event.getX();
                float moveY = event.getY();
                updateDragPoint(moveX, moveY);
                break;
            case MotionEvent.ACTION_UP:
                handleActionUp();
                break;
        }
        invalidate();
        return true;
    }
    public void initPoint(float downX, float downY) {
        mFixedPoint = new PointF(downX, downY);
        mDragPoint = new PointF(downX, downY);
        invalidate();
    }

    public void setDragBitmap(Bitmap bitmap) {
        mDragBitmap = bitmap;
    }
    /**
     * 更新拖拽点的位置
     *
     * @param moveX
     * @param moveY
     */
    public void updateDragPoint(float moveX, float moveY) {
        mDragPoint.x = moveX;
        mDragPoint.y = moveY;
        invalidate();
    }
    public void handleActionUp() {
        if (mFixedRadius > mFixedRadiusMin) {
            // 回弹  ValueAnimator 值变化的动画  0 变化到 1
            ValueAnimator animator = ObjectAnimator.ofFloat(1);
            animator.setDuration(250);
            final PointF start = new PointF(mDragPoint.x, mDragPoint.y);
            final PointF end = new PointF(mFixedPoint.x, mFixedPoint.y);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float percent = (float) animation.getAnimatedValue();// 0 - 1
                    PointF pointF = BubbleUtils.getPointByPercent(start, end, percent);
                    // 用代码更新拖拽点
                    updateDragPoint(pointF.x, pointF.y);
                }
            });
            // 设置一个差值器 在结束的时候回弹OvershootInterpolator(3f)
            animator.setInterpolator(new BounceInterpolator());
            animator.start();
            // 还要通知 TouchListener 移除当前View 然后显示静态的 View
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    if (mListener != null) {
                        mListener.restore();
                    }
                }
            });
        } else {
            // 爆炸
            if (mListener != null) {
                mListener.dismiss(mDragPoint);
            }
        }
    }
    public void setMessageBubbleListener(MessageDragListener onListener) {
        mListener = onListener;
    }

    /**
     * 绑定拖拽空间
     *
     * @param view
     * @param disappearListener
     */
    public static void attach(View view, DragDisappearListener disappearListener) {
        view.setOnTouchListener(new MessageBubbleTouchListener(view, view.getContext(),disappearListener));
    }
}
